﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Collections.ObjectModel;
using Sparkle.Lib;

namespace Sparkle.UI
{
    /// <summary>
    /// Interaction logic for DataPanel.xaml
    /// </summary>
    public partial class DataPanel : UserControl
    {
        public DataPanel()
        {
            DynamicSize = false;
            InitializeComponent();
            DataContextChanged += DataPanelDataContextChanged;
        }

        private void UserControlLoaded(object sender, RoutedEventArgs e)
        {
            if (DynamicSize && Parent != null && (this.Parent is FrameworkElement))
            {
                (Parent as FrameworkElement).SizeChanged += DataPanelSizeChanged;
            }
        }
        
        #region Events

        void DataPanelSizeChanged(object sender, SizeChangedEventArgs e)
        {
            Width = ((FrameworkElement) Parent).Width;
        }


        #endregion

        #region UI Priperties

        private Column _columns = Column.Double;

        public Column Columns
        {
            get { return _columns; }
            set { _columns = value; }
        }

        private int _labelWidth = UIUtils.LabelWidth;

        public int LabelWidth
        {
            get { return _labelWidth; }
            set { _labelWidth = value; }
        }

        private double _controlWidth = UIUtils.ControlWidth;

        public double ControlWidth
        {
            get
            {
                if (_columns == Column.Double)
                    return (_controlWidth == 250 ? FullWidth / 2 : _controlWidth);

                return (_controlWidth == 250 ? FullWidth : _controlWidth);
            }
            set { _controlWidth = value; }
        }

        public double FullWidth
        {
            get { return Width - 44/*margin and scrollview scrolbaar*/  ; }
        }

        #endregion

        #region properties


        #region DynamicSize

        /// <summary>
        /// Dynamic Size (height and width)
        /// </summary>
        public bool DynamicSize { get; set; }

        #endregion FullWidth 

        #region EnableClientValidation

        private bool _enableClientValidation = true;
        /// <summary>
        /// EnableClientValidation
        /// </summary>
        public bool EnableClientValidation
        {
            get { return _enableClientValidation; }
            set { _enableClientValidation = value; }
        }

        #endregion EnableClientValidation


        #region NotifyOnValidationError

        private bool _notifyOnValidationError = true;

        /// <summary>
        /// EnableInvalidValueValidation
        /// </summary>
        public bool NotifyOnValidationError
        {
            get { return _notifyOnValidationError; }
            set { _notifyOnValidationError = value; }
        }

        #endregion EnableInvalidValueValidation



        private Collection<GroupPanel> generatedGroupPanels = new Collection<GroupPanel>();

        //public new object DataContext
        //{
        //    get
        //    {
        //        return base.DataContext;
        //    }
        //    set
        //    {
        //        base.DataContext = value;
        //        DataPanelDataContextChanged(this,new DependencyPropertyChangedEventArgs(DataContextProperty  ,null,value));
        //    }
        //}


        void DataPanelDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            var value = e.NewValue;
            if (value == null)
            { throw new ArgumentNullException("DataContext", "DataContext can not be null"); } //NullReferenceException
            if (value is System.Collections.IEnumerable)
            { throw new ArgumentException("DataContext value can not be IEnumerable.", "DataContext"); } //InvalidCastException
            base.DataContext = value;
            ResetControls();
            Genratecontrols();
        }


        List<Metadata> _metadataList;

        public List<Metadata> MetadataList
        {
            get
            {
                return _metadataList;
            }
        }

        #endregion

        #region public methods

        #endregion


        #region Private methods

        #region resetControls

        private void ResetControls()
        {

            stkpnlMain.Children.Clear();

            generatedGroupPanels.Clear();
        }

        #endregion

        #region genratecontrols

        private void Genratecontrols()
        {
            if (DataContext == null)
                return;

            _metadataList = new List<Metadata>();

            _metadataList = MetadataProvider.GetVisibleMetadataCollection(DataContext);

            var metaGroups = _metadataList
                .GroupBy(x => new { GroupName = x.Group })
                .Select(grp => new {grp.Key.GroupName, Count = grp.Count(), metadatas = grp.AsEnumerable() })
                .OrderBy(x => x.GroupName).ThenBy(x => x.metadatas.OrderBy(m => m.Order));

            foreach (var item in metaGroups)
            {
                var groupPanel = CreateGroupPanel(item.GroupName);

                generatedGroupPanels.Add(groupPanel);

                stkpnlMain.Children.Add(groupPanel);

                var metadatas = item.metadatas.OrderBy(o => o.Order);

                foreach (var metadata in metadatas)
                {
                    if (EnableClientValidation)
                    {
                        metadata.GetValidationRules();
                    }

                    metadata.NotifyOnValidationError = NotifyOnValidationError;

                    groupPanel.Children.Add(CreateMetaControl(metadata));
                }
            }

            //metadataList.Clear();

        }

        #endregion

        #region createGroupPanel and GetGroupPanel

        private GroupPanel CreateGroupPanel(string groupName)
        {
            var groupPanel = UIDefaults.CreateGroupPanel();
            groupPanel.Title = groupName;
            groupPanel.Width = FullWidth;
            return groupPanel;
        }

        #endregion

        #region createMetaControl

        private MetaControl CreateMetaControl(Metadata metadata)
        {
            MetaControl metaControl = UIDefaults.CreateMetaControl();

            metaControl = CreateMetaControl(metadata, metaControl);

            return metaControl;
        }

        private MetaControl CreateMetaControl(Metadata metadata, MetaControl metaControl)
        {
            var tmpLabel = UIDefaults.DefaultControlFactory.CreateLabel(metadata, LabelWidth);

            var tmptCnt = SupplyAdditionalControl(metadata);

            if (tmptCnt == null && SupplyAdditionalControlDelegate != null)
                tmptCnt = SupplyAdditionalControlDelegate(metadata);

            if (tmptCnt == null)
                tmptCnt = UIDefaults.DefaultControlFactory.CreateControl(metadata);

            if (tmptCnt != null)
            {
                UIDefaults.DefaultControlFactory.SetBinding(tmptCnt, metadata, DataContext);
                tmptCnt.Tag = metadata;

                SetSize(tmptCnt, metadata);

                if (metaControl == null)
                {
                    metaControl = UIDefaults.CreateMetaControl();
                    metaControl.Width = ControlWidth;
                }

                metaControl.AddControls(tmpLabel, tmptCnt);
            }
            else
            {
                var unktblock = new TextBlock
                                    {
                                        Text = "Unknown Control",
                                        Width = (ControlWidth - LabelWidth)
                                    };

                if (metaControl == null)
                {
                    metaControl = UIDefaults.CreateMetaControl();
                    metaControl.Width = ControlWidth;
                }

                metaControl.AddControls(tmpLabel, unktblock);
            }

            if (metadata.LableAt == LabelLocation.Left)
            {
                metaControl.Orientation = Orientation.Horizontal;
                metaControl.VerticalAlignment = VerticalAlignment.Top;
            }
            else
            {
                metaControl.Orientation = Orientation.Vertical;
                metaControl.HorizontalAlignment = HorizontalAlignment.Left;
            }

            metaControl.Tag = metadata;
            return metaControl;
        }

        #endregion

        #region Setsize

        private void SetSize(Control control, Metadata metadata)
        {
            if (control != null)
                control.Margin = UIDefaults.GetMargin();

            if (metadata.Visualization != null && control != null)
            {
                if (!metadata.Visualization.AutoSize)
                {
                    if (metadata.Visualization.FullWidth)
                        control.Width = FullWidth - LabelWidth;
                    else if (metadata.Visualization.Width > 0)
                        control.Width = ControlWidth - metadata.Visualization.Width;

                    if (metadata.Visualization.Height > 0)
                    {
                        control.Height = metadata.Visualization.Height;
                        //if textbox and string then set multy line
                        if (control is TextBox && metadata.MetaType == typeof(string))
                            (control as TextBox).TextWrapping = TextWrapping.Wrap;
                    }
                }
            }

        }

        #endregion

        #endregion

        #region virtual methods

        public delegate void OverrideDefaultControldlgt(Metadata metadata, bool showLabel);

        public OverrideDefaultControldlgt OverrideDefaultControlDelegate;

        public virtual Control OverrideDefaultControl(Metadata metadata, bool showLabel)
        {
            return null;
        }

        public delegate Control DlgSupplyAdditionalControl(Metadata metadata);

        public DlgSupplyAdditionalControl SupplyAdditionalControlDelegate;

        public virtual Control SupplyAdditionalControl(Metadata metadata)
        {
            return null;
        }

        #endregion

    }
}
